import { startsWith, has, includes, findKey, values, isObject, isArray } from "lodash";
import moment from "moment";
import { getCounterData } from "@/lib/functions";
import { currentUser } from "@/../../../../client/app/services/auth";

const DATETIME_FORMATS = {
  "date-range": "YYYY-MM-DD",
  "datetime-range": "YYYY-MM-DD HH:mm",
  "datetime-range-with-seconds": "YYYY-MM-DD HH:mm:ss",
};

const DYNAMIC_PREFIX = "d_";

/**
 * Dynamic date range preset value with end set to current time
 * @param from {function(): moment.Moment}
 * @param now {function(): moment.Moment=} moment - defaults to now
 * @returns {function(withNow: boolean): [moment.Moment, moment.Moment|undefined]}
 */
const untilNow = (from, now = () => moment()) => (withNow = true) => [from(), withNow ? now() : undefined];

const DYNAMIC_DATE_RANGES = {
  now:{
    name: "今天",
    value: () => moment().startOf("day"),
  },
  today:{
    name: "今天",
    value: () => moment().startOf("day"),
  },
  yesterday: {
    name: "昨天",
    value: () => moment().subtract(1, "day"),
  },
  this_day: {
    name: "今天",
    value: () => [moment().startOf("day"), moment().endOf("day")],
  },
  last_day: {
    name: "昨天",
    value: () => [
      moment()
        .subtract(1, "day")
        .startOf("day"),
      moment()
        .subtract(1, "day")
        .endOf("day"),
    ],
  },
  this_week: {
    name: "本周",
    value: () => [moment().startOf("week"), moment().endOf("week")],
  },
  this_month: {
    name: "本月",
    value: () => [moment().startOf("month"), moment().endOf("month")],
  },
  this_quarter: {
    name: "本季",
    value: () => [moment().startOf("quarter"), moment().endOf("quarter")],
  },
  this_year: {
    name: "今年",
    value: () => [moment().startOf("year"), moment().endOf("year")],
  },
  last_week: {
    name: "上周",
    value: () => [
      moment()
        .subtract(1, "week")
        .startOf("week"),
      moment()
        .subtract(1, "week")
        .endOf("week"),
    ],
  },
  last_month: {
    name: "上月",
    value: () => [
      moment()
        .subtract(1, "month")
        .startOf("month"),
      moment()
        .subtract(1, "month")
        .endOf("month"),
    ],
  },
  last_year: {
    name: "去年",
    value: () => [
      moment()
        .subtract(1, "year")
        .startOf("year"),
      moment()
        .subtract(1, "year")
        .endOf("year"),
    ],
  },
  last_hour: {
    name: "Last hour",
    value: untilNow(() => moment().subtract(1, "hour")),
  },
  last_8_hours: {
    name: "Last 8 hours",
    value: untilNow(() => moment().subtract(8, "hour")),
  },
  last_24_hours: {
    name: "Last 24 hours",
    value: untilNow(() => moment().subtract(24, "hour")),
  },
  last_7_days: {
    name: "近7天",
    value: untilNow(
      () =>
        moment()
          .subtract(6, "days")
          .startOf("day"),
      () => moment().endOf("day")
    ),
  },
  last_14_days: {
    name: "近14天",
    value: untilNow(
      () =>
        moment()
          .subtract(13, "days")
          .startOf("day"),
      () => moment().endOf("day")
    ),
  },
  last_30_days: {
    name: "近30天",
    value: untilNow(
      () =>
        moment()
          .subtract(29, "days")
          .startOf("day"),
      () => moment().endOf("day")
    ),
  },
  last_60_days: {
    name: "近60天",
    value: untilNow(
      () =>
        moment()
          .subtract(59, "days")
          .startOf("day"),
      () => moment().endOf("day")
    ),
  },
  last_90_days: {
    name: "近90天",
    value: untilNow(
      () =>
        moment()
          .subtract(89, "days")
          .startOf("day"),
      () => moment().endOf("day")
    ),
  },
  last_12_months: {
    name: "前12个月",
    value: untilNow(
      () =>
        moment()
          .subtract(12, "months")
          .startOf("day"),
      () => moment().endOf("day")
    ),
  },
};

export function isDynamicDateRangeString(value) {
  if (!startsWith(value, DYNAMIC_PREFIX)) {
    return false;
  }
  return !!DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_PREFIX.length)];
}

export function getDynamicDateRangeStringFromName(dynamicRangeName) {
  const key = findKey(DYNAMIC_DATE_RANGES, range => range.name === dynamicRangeName);
  return key ? DYNAMIC_PREFIX + key : undefined;
}

export function isDynamicDateRange(value) {
  return includes(DYNAMIC_DATE_RANGES, value);
}

export function getDynamicDateRangeFromString(value) {
  if (!isDynamicDateRangeString(value)) {
    return null;
  }
  return DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_PREFIX.length)];
}

export function getUrlParameterValue(parameter) {
  let parameterValue = "";
  let paramterstr = "p_" + parameter;
  let searchURL = window.location.search;
  if (searchURL.includes(paramterstr)) {
    if (searchURL.indexOf(paramterstr + "=") > 0) {
      searchURL = searchURL.substring(searchURL.indexOf(paramterstr + "="), searchURL.length);
    } else if (searchURL.indexOf(parameter + "=") > 0) {
      searchURL = searchURL.substring(searchURL.indexOf(parameter + "="), searchURL.length);
    }
    parameterValue = decodeURIComponent(searchURL.split("&")[0].split("=")[1]);
  }
  return parameterValue;
}

export function getUrlParameters(parameters) {
  for (let param in parameters) {
    if (parameters[param].toString().indexOf("currentUser::") === 0) {
      const userProperty = parameters[param].toString().substring(13);
      if (currentUser.hasOwnProperty(userProperty)) {
        parameters[param] = currentUser[userProperty];        
      }
    }

    if (parameters[param].toString().indexOf("parameter::") === 0) {
      let paramValue = "";
      let paramstr = parameters[param].toString().replace("parameter::","");
      let paramURL = window.location.search;
      if (paramURL.includes(paramstr)) {
        if (paramURL.indexOf("p_" + paramstr + "=") > 0) {
          paramURL = paramURL.substring(paramURL.indexOf("p_" + paramstr + "="), paramURL.length);
        } else if (paramURL.indexOf(paramstr + "=") > 0) {
          paramURL = paramURL.substring(paramURL.indexOf(paramstr + "="), paramURL.length);
        }
        paramValue = decodeURIComponent(paramURL.split("&")[0].split("=")[1]);
        if (isDynamicDateRangeString(paramValue.toString())) {
          const normalizedValue = getDynamicDateRangeFromString(paramValue.toString()).value()
          if (normalizedValue instanceof Array) {
            const startValue = normalizedValue[0].format("YYYY-MM-DD");
            const endValue = normalizedValue[1].format("YYYY-MM-DD");
            paramValue = {start:startValue, end:endValue};
          } else {
            paramValue = normalizedValue.format("YYYY-MM-DD");
          }
        } else if (paramValue.toString().indexOf("[") === 0 && paramValue.toString().lastIndexOf("]") === paramValue.toString().length-1) {
          paramValue = JSON.parse(paramValue.toString())
        }
        if (paramValue.toString().includes("--") && paramValue.toString().split("--").length === 2) {
          paramValue = {start:paramValue.toString().split("--")[0], end:paramValue.toString().split("--")[1]}
        }
      }
      parameters[param] = paramValue;        
    }
  }  
  return parameters;
}

export function replaceUrlParameter(origin, data=undefined) {
  var mats = /\{\{(.|\n)*?\}\}/m.exec(origin);
  while (mats && mats instanceof Array) {
    let oldstr = mats[0].toString();
    let functions;
    try {
      let objstr = oldstr.substring(1, oldstr.length-1)
      functions = JSON.parse(objstr);
    } catch(e) {      
      return origin.replace(oldstr, e);
    }
    if (functions.hasOwnProperty("parameter")) {
      let parameterValue = getUrlParameterValue(functions.parameter)
      origin = origin.replace(oldstr, parameterValue);
    } else if (data && (functions.hasOwnProperty("query") || functions.hasOwnProperty("querys"))) {
      let query = functions.query || functions.querys;
      if (!!!query || parseInt(query) === 0) {
        delete functions.query
        delete functions.querys
        delete functions.parameters
        let result = getCounterData(data.rows, functions);
        origin = origin.replace(oldstr, result);
      } else {
        origin = origin.replace(oldstr, "");
      }
    } else {
      origin = origin.replace(oldstr, "");
    }

    mats = /\{\{(.|\n)*?\}\}/m.exec(origin);
  }
  return origin;
}